package org.activequant.tradesystem.ib;
import org.activequant.container.ITradeSystemContextThread;
import org.activequant.core.domainmodel.marketscanner.MarketScan;
import org.activequant.core.domainmodel.marketscanner.ScanDataEntity;
import org.activequant.data.retrieval.IScanDataReplayService;
import org.apache.log4j.Logger;

/**
 * The ScanBacktestRunner fetches from the replay service all 
 * scandata entities and triggers the replay service's fire method. <br/>
 * An ITradeSystemContextThread implementation. Holds the following associated variable:
 * <ul>
 * <li>replayService(IScanDataReplayService)</li>
 * </ul>
 * @author Dimitar Misev
 */
public class ScanBacktestRunner implements ITradeSystemContextThread {
	
	private static final Logger log = Logger.getLogger(ScanBacktestRunner.class);
	/**
	 * private IScanDataReplayService replayService;
	 */
	private IScanDataReplayService replayService;
	
	public static int NUMBER_OF_SCANNERS=0;
	
	/**
	 * an empty BacktestRunner(ITradeSystemContextThread implementation) constructor
	 */
	public ScanBacktestRunner() { }
	/**
	 * constructs a BacktestRunner(ITradeSystemContextThread implementation) using the given replayService(IScanDataReplayService) 
	 * to set its associated replayService(IScanDataReplayService)
	 * @param replayService
	 */
	public ScanBacktestRunner(IScanDataReplayService replayService) {
		this.replayService = replayService;
	}
	
	public void run() {
		log.info("running backtester");
		int STREAMS_PER_SCAN=1;
		while (replayService.getStreamsSize()< (NUMBER_OF_SCANNERS*STREAMS_PER_SCAN)){
			try {
				log.info("sleeping 1 sec");
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		int count = 0;
		int marketScanCount = 0;
        long myStartTimeStamp = System.currentTimeMillis();
		try {
			for (ScanDataEntity<?> entity : replayService) {
				++count;
				
				if(MarketScan.class.isAssignableFrom(entity.getClass())) {
					++marketScanCount;
				}else{
					log.info("unhandled case:" + entity.getClass().getSimpleName());
				}
				replayService.fire(entity);
				//log.debug("fired " + entity +"("+entity.getClass().getSimpleName()+")"+ " for instrument: " + entity.getInstrumentSpecification());
			}
		} catch (Exception ex) {
			ex.printStackTrace();
			log.error(ex);
		}
        long myEndTimeStamp = System.currentTimeMillis();        
        double myElapsedTime = myEndTimeStamp - myStartTimeStamp; 

        log.info("Backtester completed. Fired " + count + " events in " + (myElapsedTime/1000) + " seconds." );
        log.info("Breakdown " + marketScanCount +" marketScans.");
        // computing the events per second.
        if (myElapsedTime != 0) {
            double myThroughput = (count / myElapsedTime) * 1000.0;
            log.info("Throughput was " + myThroughput + "/s data entities.");
        }
	}
	/**
	 * returns the associated replayService(IScanDataReplayService)
	 * @return
	 */
	public IScanDataReplayService getReplayService() {
		return replayService;
	}
	/**
	 * sets the associated replayService(IScanDataReplayService) with the given replayService(IScanDataReplayService)
	 * @param replayService
	 */
	public void setReplayService(IScanDataReplayService replayService) {
		this.replayService = replayService;
	}

}